package keyboard;

import java.util.HashMap;
import java.util.HashSet;

public class GroupCostCalculatorUsingFittsLaw extends GroupCostCalculator {
	final float CODE_VS = 0.5215977f;
	final float[] SCAN_VS = {0f, 0.4029847f, 0.5196843f, 0.8694614f, 1.2672222f};
	final float NEXT_VS = 1.0188424f;
	final float A = 0.59020652f, B = 0.24370553f; 
	
	Position codeEndPosition;
	
	public GroupCostCalculatorUsingFittsLaw(Keyboard keyboard, HashSet<Character> keysGroup, HashMap<Character, Float> keysValue, Position lastPosition) {
		super(keyboard, keysGroup, keysValue, lastPosition);
	}
	
	private float calnFittsLaw(Position startPosition, Position endPosition, Position size) {
		float D = Position.EuclidDist(startPosition, endPosition);
		float W = Math.min(size.r, size.c);
		float cost = A + B * (float)(Math.log(D / W + 1) / Math.log(2f));
		return cost;
	}
	
	@Override
	public float GetTheCostOfPriority(int priority) {
		float scanCost = 0f;
		int pos = (priority - 1) % 4 + 1;
		int page = (priority - 1) / 4 + 1;
		if (priority <= 4) {
			Position confirmCentre = keyboard.GetSelectorCentrePosition(pos);
			Position confirmSize = keyboard.GetSelectorSize();
			Position confirmPosition = Position.getPressPosition(codeEndPosition, confirmCentre, confirmSize);
			scanCost += calnFittsLaw(codeEndPosition, confirmPosition, confirmSize) + SCAN_VS[pos];
		} else {
			Position nextCentre = keyboard.GetNextCentrePosition();
			Position nextSize = keyboard.GetSelectorSize();
			Position nextPosition = Position.getPressPosition(codeEndPosition, nextCentre, nextSize);
			Position confirmCentre = keyboard.GetSelectorCentrePosition(pos);
			Position confirmSize = keyboard.GetSelectorSize();
			Position confirmPosition = Position.getPressPosition(nextPosition, confirmCentre, confirmSize);
			scanCost += calnFittsLaw(codeEndPosition, nextPosition, nextSize) + (page - 1) * NEXT_VS;
			scanCost += calnFittsLaw(nextPosition, confirmPosition, confirmSize) + SCAN_VS[pos];
		}
		return scanCost;
	}

	@Override
	public float GetExpectedCost() {
		Position thisCentre = keyboard.GetGroupCentrePosition(keysGroup);
		Position thisSize = keyboard.GetGroupSize(keysGroup);
		codeEndPosition = Position.getPressPosition(lastPosition, thisCentre, thisSize);
		float codeCost = calnFittsLaw(lastPosition, codeEndPosition, thisSize) + CODE_VS;

		float groupValue = keyboard.CalnGroupValue(keysGroup, keysValue);
		return codeCost * groupValue + GetSelectingCost();
	}
}
